let _Vue = null
export default class VueRouter{
  // 两个参数：vue的构造函数、可选的选项对象。
  static install (Vue) {
    // 1、判断当前插件是否已安装
    if(VueRouter.install.installed){
      return;
    }
    VueRouter.install.installed = true;

    // 2、把Vue构造函数记录到全局变量
    // 因为将来要在vuerouter的实例方法中使用vue构造函数。如创建组件时：Vue.component
    _Vue = Vue;
    // 3、把创建Vue实例时候传入的router对象注入到所有Vue实例上$router
    // 所有的实例共享一个成员，应该把它设置到构造函数原型上。
    // 使用混入 在插件里，可给所有实例混入一个选项，选项可设置beforeCreate,在这个钩子函数中可获取到Vue实例，并给原型上注入$router
    _Vue.mixin({
      // 所有组件都会有beforeCreate，而我们挂在$router只需要执行一次，应该判断一下组件的话就不执行了，vue实例的话执行
      beforeCreate(){
        if (this.$options.router) {
          _Vue.prototype.$router = this.$options.router;
          this.$options.router.init();
        }
      }
    })
  }

  constructor (options) {
    // 记录构造函数中传入的选项
    this.options = options;
    // 将options中传入的routes路由规则 解析出来 放在 routeMap中
    this.routeMap = {};
    // 响应式的，里面有个current记录当前路由地址。默认是'/'根目录
    // vue中提供observable方法创建响应式对象，可直接用到渲染函数或者计算属性里面
    this.data = _Vue.observable({
      current : "/"
    })
  }

  createRouteMap () {
    // 遍历所有的路由规则，把路由规则解析成键值对的形式 存储到routeMap中
    this.options.routes.forEach(route => {
      this.routeMap[route.path] = route.component;
    })
  }

    // 不适用_Vue是减少对外部依赖
  initComponents (Vue) {
    Vue.component("router-link", {
      props: {
        to: String
      },
      // h函数帮我们创建虚拟DOM 使用方式有很多，
      // 可接受三个参数：要创建元素的选择器、设置一些属性对象、生成元素中的子元素
      render (h) {
        return h('a', {
            attrs: {
                href: this.to
            },
            // 注册事件
            on: {
                click: this.clickHandler
            }
        }, [this.$slots.default])
      },
      methods: {
        clickHandler (e) {
            e.preventDefault();
            // 1、调用pushState方法改变浏览器地址栏，但不向服务器发送请求
            // 三个参数： data事件对象、title网页标题、url跳转的地址
            history.pushState({}, "", this.to);
            // 2、把当前路径记录到data.current中,
            // 因为是响应式的对象，值改变之后，重新加载对应的组件，并重新渲染
            this.$router.data.current = this.to;
        }
      }
      // template: "<a :href='to'><slot></slot></a>"
    })

    const that = this;
    Vue.component("router-view",{
        render (h) {
            const component = that.routeMap[that.data.current]
            return h(component)
        }
    })
  }

  init() {
    this.createRouteMap();
    this.initComponents(_Vue);
    this.initEvent();
  }

  initEvent () {   
      window.addEventListener("popstate", () => {
          this.data.current = location.hash.slice(1)
      })
  }
}